home *** CD-ROM | disk | FTP | other *** search
/ Super PC 33 / Super PC 33 (Shareware).iso / spc / sonido / timidity / source / wave_aud.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-06  |  4.7 KB  |  195 lines

  1. /*
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <titoivon@snakemail.hut.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.      GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     wave_audio.c
  21.  
  22.      Functions to output RIFF WAVE format data to a file or stdout.
  23.  
  24. */
  25.  
  26. #ifdef __WIN32__
  27. #include <stdlib.h>
  28. #include <io.h>
  29. #include <string.h>
  30. #else
  31. #include <unistd.h>
  32. #endif
  33. #include <fcntl.h>
  34. #include <errno.h>
  35.  
  36. #ifdef __FreeBSD__
  37. #include <stdio.h>
  38. #endif
  39.  
  40. #include "config.h"
  41. #include "output.h"
  42. #include "controls.h"
  43.  
  44. #ifdef __WIN32__
  45. #define OPEN_MODE O_WRONLY | O_CREAT | O_TRUNC | O_BINARY
  46. #else
  47. #define OPEN_MODE O_WRONLY | O_CREAT | O_TRUNC
  48. #endif
  49.  
  50. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  51. static void close_output(void);
  52. static void output_data(int32 *buf, int32 count);
  53. static void flush_output(void);
  54. static void purge_output(void);
  55.  
  56. /* export the playback mode */
  57.  
  58. #define dpm wave_play_mode
  59.  
  60. PlayMode dpm = {
  61.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  62.   -1,
  63.   {0},
  64.   "RIFF WAVE file", 'w',
  65.   "output.wav",
  66.   open_output,
  67.   close_output,
  68.   output_data,
  69.   flush_output,
  70.   purge_output
  71. };
  72.  
  73. /*************************************************************************/
  74.  
  75. static char *orig_RIFFheader=
  76.   "RIFF" "\377\377\377\377" 
  77.   "WAVE" "fmt " "\020\000\000\000" "\001\000"
  78.   /* 22: channels */ "\001\000" 
  79.   /* 24: frequency */ "xxxx" 
  80.   /* 28: bytes/second */ "xxxx" 
  81.   /* 32: bytes/sample */ "\004\000" 
  82.   /* 34: bits/sample */ "\020\000"
  83.   "data" "\377\377\377\377"
  84. ;
  85.  
  86. /* Count the number of bytes output so the header can be fixed when
  87.    closing the file */
  88. static int32 bytes_output;
  89.  
  90. /* We only support 16-bit signed and 8-bit unsigned data -- WAVEs have
  91.     to be supported because TiMidity is a "MIDI-to-WAVE converter"...
  92.  
  93.    uLaw WAVEs might be useful and not too hard to implement. I just
  94.    don't know what should go in the "fmt " block. */
  95.  
  96. static int open_output(void)
  97. {
  98.   char RIFFheader[44];
  99.   int t;
  100.  
  101.   dpm.encoding &= ~(PE_BYTESWAP|PE_ULAW);
  102.   if (dpm.encoding & PE_16BIT) 
  103.     dpm.encoding |= PE_SIGNED;
  104.   else 
  105.      dpm.encoding &= ~PE_SIGNED;
  106.  
  107.   if (dpm.name && dpm.name[0]=='-' && dpm.name[1]=='\0')
  108.     dpm.fd=1; /* data to stdout */
  109.   else
  110.     {
  111.         /* Open the audio file */
  112.         dpm.fd=open(dpm.name, OPEN_MODE, 0644);
  113.         if (dpm.fd<0)
  114.     {
  115.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
  116.              dpm.name, sys_errlist[errno]);
  117.       return -1;
  118.     }
  119.      }
  120.  
  121.   /* Generate a (rather non-standard) RIFF header. We don't know yet
  122.      what the block lengths will be. We'll fix that at close if this
  123.      is a seekable file. */
  124.  
  125.   memcpy(RIFFheader, orig_RIFFheader, 44);
  126.   
  127.   if (!(dpm.encoding & PE_MONO)) RIFFheader[22]='\002';
  128.  
  129.   *((int *)(RIFFheader+24))=LE_LONG(dpm.rate);
  130.  
  131.   t=dpm.rate; 
  132.   if (!(dpm.encoding & PE_MONO)) t*=2;
  133.   if (dpm.encoding & PE_16BIT) t*=2;
  134.   *((int *)(RIFFheader+28))=LE_LONG(t);
  135.  
  136.   if ((dpm.encoding & (PE_MONO | PE_16BIT)) == PE_MONO)
  137.     RIFFheader[32]='\001';
  138.   else if (!(dpm.encoding & PE_MONO) || (dpm.encoding & PE_16BIT))
  139.     RIFFheader[32]='\002';
  140.  
  141.   if (!(dpm.encoding & PE_16BIT)) RIFFheader[34]='\010';
  142.  
  143.   write(dpm.fd, RIFFheader, 44);
  144.  
  145.   /* Reset the length counter */
  146.   bytes_output=0;
  147.  
  148.   return 0;
  149. }
  150.  
  151. static void output_data(int32 *buf, int32 count)
  152. {
  153.   if (!(dpm.encoding & PE_MONO)) count*=2; /* Stereo samples */
  154.   
  155.   if (dpm.encoding & PE_16BIT)
  156.     {
  157.         s32tos16l(buf, NULL, count); /* Little-endian data */
  158.  
  159.       while ((-1==write(dpm.fd, buf, count * 2)) && errno==EINTR)
  160.     ;
  161.       bytes_output += count*2;
  162.     }
  163.   else
  164.     {
  165.         s32tou8(buf, NULL, count);
  166.  
  167.         while ((-1==write(dpm.fd, buf, count)) && errno==EINTR)
  168.     ;
  169.         bytes_output += count;
  170.      }
  171. }
  172.  
  173. static void close_output(void)
  174. {
  175.   if (dpm.fd != 1) /* We don't close stdout */
  176.      {
  177.         /* It's not stdout, so it's probably a file, and we can try
  178.             fixing the block lengths in the header before closing. */
  179.         if (lseek(dpm.fd, 4, SEEK_SET)>=0)
  180.     {
  181.       int32 tmp;
  182.       tmp=LE_LONG(bytes_output + 44 - 8);
  183.       write(dpm.fd, &tmp, 4);
  184.       lseek(dpm.fd, 40, SEEK_SET);
  185.       tmp=LE_LONG(bytes_output);
  186.       write(dpm.fd, &tmp, 4);
  187.     }
  188.       close(dpm.fd);
  189.     }
  190. }
  191.  
  192. /* Dummies */
  193. static void flush_output(void) { }
  194. static void purge_output(void) { }
  195.